About      Forum      Issues      Tutorials      Documentation </span>

Tutorial 3: Intro to Quantum Chemistry

This tutorial shows how to select a quantum chemistry method, visualize orbitals, and analyze the electronic wavefunction.


In [ ]:
%matplotlib inline
import numpy as np
from matplotlib.pylab import *
try: import seaborn  #optional, makes plots look nicer
except ImportError: pass

import moldesign as mdt
from moldesign import units as u

I. Build and minimize minimal basis set hydrogen

A. Build the molecule

This cell builds H2 by creating the two atoms, and explicitly setting their positions.

Try editing this cell to:

  • Create HeH+
  • Create H3+
  • Change the atoms' initial positions

In [ ]:
atom1 = mdt.Atom('H')
atom2 = mdt.Atom('H')
atom1.bond_to(atom2,1)
atom2.x = 2.0 * u.angstrom

h2 = mdt.Molecule([atom1,atom2], name='H2', charge=0)
h2.draw(height=300)

B. Run a hartree-fock calculation

The next cell adds the RHF energy model to our molecule, then triggers a calculation.

Try editing this cell to:

  • Change the atomic basis
  • Get a list of other available energy models (type mdt.models. and then hit the [tab] key)

In [ ]:
h2.set_energy_model(mdt.models.RHF, basis='3-21g')
h2.calculate()

print 'Calculated properties:', h2.properties.keys()
print 'Potential energy:', h2.potential_energy

C. Visualize the orbitals

After running the calculation, we have enough information to visualize the molecular orbitals.


In [ ]:
h2.draw_orbitals()

D. Minimize the energy

Here, we'll run a quick energy minimization then visualize how the hydrogen nuclei AND the atomic wavefunctions changed.


In [ ]:
minimization = h2.minimize(frame_interval=1, nsteps=10)
minimization.draw_orbitals()

II. Analyzing the wavefunction

The wavefunction created during QM calculations will be stored as an easy-to-analyze python object:


In [ ]:
wfn = h2.wfn
wfn

A. The atomic basis set

First, let's examine the atomic orbitals. The overlaps, fock matrix, coefficents, and density matrix are all available as 2D numpy arrays (with units where applicable):


In [ ]:
# Overlap matrix
wfn.aobasis.overlaps

In [ ]:
# Fock matrix
matshow(wfn.aobasis.fock.value_in(u.eV))
colorbar(label='fock element / eV')

In [ ]:
# The AO orbital coefficients (in the AO basis, this is the identity)
wfn.aobasis.coeffs

In [ ]:
wfn.aobasis.density_matrix

The 1- and 2-electron parts of the hamiltonian are also available:


In [ ]:
matshow(wfn.aobasis.h1e.value_in(u.eV))
colorbar(label='1-electron hamiltonian term / eV')

matshow(wfn.aobasis.h2e.value_in(u.eV))
colorbar(label='2-electron hamiltonian term / eV')

B. The canonical molecular orbitals

These are the orbitals that result from Hartree-Fock calculations - they diagonalize the fock matrix. All quantities that we looked at for the atomic orbitals are also available for the canonical orbitals.


In [ ]:
mos = wfn.orbitals.canonical
mos

MOs are, of course, a linear combination of AOs:

\begin{equation} \left| \text{MO}_i \right \rangle = \sum_j c_{ij} \left| \text{AO}_j \right\rangle \end{equation}

The coefficient $c_{ij}$ is stored at mos.coeffs[i,j]


In [ ]:
mos.coeffs

Most MO sets are orthogonal; their overlaps will often be the identity matrix (plus some small numerical noise)


In [ ]:
mos.overlaps

By definition, the fock matrix should be orthogonal as well; the orbital energies are on its diagonal.


In [ ]:
matshow(mos.fock.value_in(u.eV))
colorbar(label='fock element/eV')

The MolecularOrbitals class also offers several methods to transform operators into different bases. For instance, the overlap method creates an overlap matrix between the AOs and MOs, where olap[i,j] is the overlap between MO i and AO j: \begin{equation} \text{olap[i,j]} = \left\langle MO_i \middle| AO_j \right \rangle \end{equation}

Note: this matrix is NOT the same as the MO coefficient matrix, because AOs are not orthogonal.


In [ ]:
olap = mos.overlap(wfn.aobasis)
olap

C. Individual orbitals

You can work with inidividual orbitals as well. For instance, to get a list (in order) of the four AOs:


In [ ]:
wfn.aobasis.orbitals

In [ ]:
ao0 = wfn.aobasis.orbitals[0]
ao1 = wfn.aobasis.orbitals[1]

print ao0
print ao1

Many matrix elements can also be accessed directly from these orbitals.


In [ ]:
print 'overlap (from orbitals)',ao0.overlap(ao1)
print 'overlap (from overlap matrix)', wfn.aobasis.overlaps[0,1]
print
print 'fock element (from orbitals)', ao0.fock_element(ao1)
print 'fock element (from fock matrix)', wfn.aobasis.fock[0,1]